import { Service } from 'egg';
//import { Template } from '../model/Template';
import * as Jsapi from 'wechat_interaction_jsapi';
import * as fs from 'fs';
import * as https from 'https';
import { Template } from '../model/Template';

export default class TemplateService extends Service {
    /**
     * 获取access_token
     */
    public async getAccessToken() {
        const appId = this.app.config.weixin.appId;
        const appSecret = this.app.config.weixin.appSecret;
        const jssdk = new Jsapi(appId, appSecret);
        const access_token = await jssdk.getAccessToken();
        return access_token;
    }

    /**
     * 获取jsapi_ticket
     */
    public async getJsapiTicket() {
        const appId = this.app.config.weixin.appId;
        const appSecret = this.app.config.weixin.appSecret;
        const jssdk = new Jsapi(appId, appSecret);
        const jsapi_ticket = await jssdk.getJsApiTicket();
        return jsapi_ticket;
    }

    /**
     * 获取签名
     */
    public async getSignPackage(param: any) {
        const appId = this.app.config.weixin.appId;
        const appSecret = this.app.config.weixin.appSecret;
        const jssdk = new Jsapi(appId, appSecret);
        const signPackage = await jssdk.getSignPackage(param.url);
        return signPackage;
        // console.log(param);
        // const submitData:any={};
        // submitData.school_id=this.ctx.helper.genUUID()+'dddd';
        // const result:any=await this.ctx.model.School.create(submitData);
        // console.log(result);
    }

    /**
     * 获取微信模板列表
     */
    public async getTemplateList() {
        let result: any = await this.checkAccessTokenAndGetTemplate();
        // 如果是access_token无效，就删了原来的access_token，获取一次模板列表
        const errcode = result.errcode;
        if (errcode && errcode === 40001) {
            fs.unlinkSync('access_token.json');
            return await this.checkAccessTokenAndGetTemplate();
        }
        for (let i = 0; i < result.template_list.length; i++) {
            const keyArr = await this.ctx.helper.keyExg(result.template_list[i].content);
            const labelArr = await this.ctx.helper.labelExg(result.template_list[i].content);
            result.template_list[i].keyArr = keyArr;
            result.template_list[i].labelArr = labelArr;
        }
        return result;
    }

    public async checkAccessTokenAndGetTemplate() {
        const access_token = await this.getAccessToken();
        const url = `https://api.weixin.qq.com/cgi-bin/template/get_all_private_template?access_token=${access_token}`;
        const result = await this.ctx.helper.wechatCode(url);
        return result;
    }

    /**
     * 创建自定义模板
     * @param param 
     */
    public async createdTemplate(param: any) {
        const submitData: any = {};
        submitData.template_id = this.ctx.helper.genUUID();
        submitData.template_template_id = param.template_id;
        submitData.template_title = param.template_title;
        submitData.template_type = param.template_type;
        submitData.user_list = param.user_list;
        submitData.template_content = param.template_content;
        submitData.is_delete = '1';
        const is_send = param.is_send;
        let resultTemplate = await this.ctx.model.Template.create(submitData);
        if (!resultTemplate) {
            throw new Error(JSON.stringify({ code: 2, msg: '创建失败' }));
        }
        if (is_send == 1) {
            const tran = await this.ctx.model.transaction();
            try {
                const date = new Date();
                const dateTime = date.toLocaleString();
                await this.ctx.model.Template.update({ template_send_time: dateTime }, { where: { template_id: submitData.template_id }, transaction: tran });
                const sendData: any = { template_id: submitData.template_id };
                const result = await this.remindUserReceive(sendData);
                if (result.success <= 0) {
                    throw new Error(JSON.stringify({ code: 2, msg: '发送失败' }));
                }
                const message: any = {};
                message.message_id = this.ctx.helper.genUUID();
                message.template_id = submitData.template_id;
                await this.ctx.model.Message.create(message, { transaction: tran });
                await tran.commit();
                return result;
            } catch (e) {
                this.ctx.logger.error(e);
                await tran.rollback();
                throw new Error(JSON.stringify({ code: 2, msg: '创建成功但发送失败' }));
            }
        }
    }

    /**
     * 删除自定义模板
     * @param param 
     */
    public async deleteTemplate(param: any) {
        const result = await this.ctx.model.Template.update({ is_delete: '2' }, { where: { template_id: param.template_id } });
        if (result[0] <= 0) {
            throw new Error(JSON.stringify({ code: 2, msg: '删除失败' }));
        }
    }

    /**
     * 查询自定义模板
     * @param param 
     */
    public async searchTemplate(param: any) {
        const page = Number(param.page);
        const size = Number(param.size);
        const limit = (page - 1) * size;
        const submitData: any = {};
        let queryStr = `SELECT template_id,template_template_id,template_title,template_type,user_list,template_content,template_send_time
        FROM t_template WHERE is_delete='1'`;
        if (param.template_title) {
            queryStr += ` AND template_title LIKE :template_title`;
            submitData.template_title = '%' + param.template_title + '%';
        }
        if (param.template_send_time) {
            queryStr += ` AND template_send_time LIKE :template_send_time`;
            submitData.template_send_time = '%' + param.template_send_time + '%';
        }
        const queryCount = queryStr;
        queryStr += ` limit ${limit},${size}`;
        const result: any = await this.ctx.model.query(queryStr, {
            type: this.ctx.model.QueryTypes.SELECT,
            replacements: submitData
        })
        const count: any = await this.ctx.model.query(queryCount, {
            type: this.ctx.model.QueryTypes.SELECT,
            replacements: submitData
        })
        if (result.length <= 0) {
            throw new Error(JSON.stringify({ code: 2, msg: '没有数据' }));
        }
        const returnData = {
            count: count.length,
            templateList: result
        }
        return returnData;
    }

    /**
     * 修改自定义模板
     * @param param 
     */
    public async editTemplate(param: any) {
        const template_id = param.template_id;
        const is_send = param.is_send;
        if (is_send == 1) {
            const tran = await this.ctx.model.transaction();
            const date = new Date();
            const dateTime = date.toLocaleString();
            const resultUpdate: any = await this.ctx.model.Template.update(
                {
                    template_template_id: param.template_template_id,
                    template_title: param.template_title,
                    template_type: param.template_type,
                    user_list: param.user_list,
                    template_content: param.template_content,
                    template_send_time: dateTime
                },
                {
                    where: { template_id }
                }
            );
            if (resultUpdate[0] <= 0) {
                throw new Error(JSON.stringify({ code: 2, msg: '更新失败' }));
            }
            try {
                const sendData: any = { template_id: template_id };
                const result = await this.remindUserReceive(sendData);
                if (result.success <= 0) {
                    throw new Error(JSON.stringify({ code: 2, msg: '修改成功-发送失败' }));
                }
                const message: any = {};
                message.message_id = this.ctx.helper.genUUID();
                message.template_id = template_id;
                await this.ctx.model.Message.create(message, { transaction: tran });
                await tran.commit();
                return result;
            } catch (e) {
                this.ctx.logger.error(e);
                await tran.rollback();
                throw new Error(JSON.stringify({ code: 2, msg: '修改成功-发送失败' }));
            }
        } else {
            const result = await this.ctx.model.Template.update(
                {
                    template_template_id: param.template_template_id,
                    template_title: param.template_title,
                    template_type: param.template_type,
                    user_list: param.user_list,
                    template_content: param.template_content
                },
                {
                    where: { template_id }
                }
            );
            if (result[0] <= 0) {
                throw new Error(JSON.stringify({ code: 2, msg: '更新失败' }));
            }
        }
    }

    /**
     * 查找消息历史
     * @param param 
     */
    public async searchMessage(param: any) {
        const page = Number(param.page);
        const size = Number(param.size);
        const limit = (page - 1) * size;
        const submitData: any = {};
        let queryStr = `SELECT t.template_title,t.template_type,t.template_content,m.created_at
        FROM t_message m INNER JOIN t_template t ON m.template_id=t.template_id`;
        if (param.template_title) {
            queryStr += ` AND t.template_title LIKE :template_title`;
            submitData.template_title = '%' + param.template_title + '%';
        }
        if (param.template_send_time) {
            queryStr += ` AND m.created_at LIKE :template_send_time`;
            submitData.template_send_time = '%' + param.template_send_time + '%';
        }
        const queryCount = queryStr + ` ORDER BY m.created_at DESC`;
        queryStr += ` ORDER BY m.created_at DESC limit ${limit},${size}`;
        const result: any = await this.ctx.model.query(queryStr, {
            type: this.ctx.model.QueryTypes.SELECT,
            replacements: submitData
        })
        const count: any = await this.ctx.model.query(queryCount, {
            type: this.ctx.model.QueryTypes.SELECT,
            replacements: submitData
        })
        if (result.length <= 0) {
            throw new Error(JSON.stringify({ code: 2, msg: '没有数据' }));
        }
        const returnData = {
            count: count.length,
            templateList: result
        }
        return returnData;
    }

    /**
     * 发送消息
     * @param param 
     */
    public async sendMessage(param: any) {
        const tran = await this.ctx.model.transaction();
        try {
            const result: any = await this.remindUserReceive(param);
            if (result.success <= 0) {
                throw new Error(JSON.stringify({ code: 2, msg: '发送失败' }));
            }
            const message: any = {};
            message.message_id = this.ctx.helper.genUUID();
            message.template_id = param.template_id;
            await this.ctx.model.Message.create(message, { transaction: tran });
            const date = new Date();
            const dateTime = date.toLocaleString();
            await this.ctx.model.Template.update({ template_send_time: dateTime }, { where: { template_id: param.template_id }, transaction: tran });
            await tran.commit();
            return result;
        } catch (e) {
            await tran.commit();
            this.ctx.logger.error(e);
            throw new Error(JSON.stringify({ code: 2, msg: '发送失败' }));
        }
    }
    /**
    * @desc 发送消息
    * @author zhu
    * @date 2018/8/7
    */
    public async remindUserReceive(param: any) {
        const resultTemplate: any = await this.ctx.model.Template.findOne<Template>({
            attributes: ['template_template_id', 'template_type', 'user_list', 'template_content'],
            where: { template_id: param.template_id }
        });
        if (!resultTemplate) {
            throw new Error(JSON.stringify({ code: 2, msg: '没有找到该模板' }));
        }
        const template_id = resultTemplate.template_template_id;
        const template_type = resultTemplate.template_type;
        let user_list_str: string = '';
        if (template_type == 1) {
            user_list_str = await this.getTokenList();
        } else {
            user_list_str = resultTemplate.user_list;
        }
        const user_list: any = user_list_str.split(',');
        const template_content: any = JSON.parse(resultTemplate.template_content);
        let newData = {};
        for (const key in template_content) {
            newData[key] = { value: template_content[key] }
        }
        let success: number = 0;
        let fail: number = 0;
        const item: any = [];
        const url = '';
        for (let i = 0; i < user_list.length; i++) {
            const result = await this.sendWechatMsg(url, newData, user_list[i], template_id);
            if (JSON.parse(result).errcode === 0) {
                success++;
                this.ctx.logger.info('发送成功');
            } else if (JSON.parse(result).errcode === 43004) {
                this.ctx.logger.error('客户已取消关注公众号！');
                fail++;
                const itemMsg: any = {};
                itemMsg.openId = user_list[i];
                itemMsg.msg = '客户已取消关注公众号！';
                item.push(itemMsg);
                continue;
                //throw new Error(JSON.stringify({ code: 2, msg: '客户已取消关注公众号！' }));
            } else {
                this.ctx.logger.error(result);
                fail++;
                const itemMsg: any = {};
                itemMsg.openId = user_list[i];
                itemMsg.msg = result;
                item.push(itemMsg);
                continue;
                //throw new Error(JSON.stringify({ code: 2, msg: result }));
            }
        }
        const result: any = { success, fail, failList: item };
        return result;
    }


    /**
     * @desc 发送模版消息
     * @author zhu
     * @date 2018/5/4
     */
    public async sendWechatMsg(url, data, openId, templateId) {
        const result: any = await this.sendWechatMsgMethod(url, data, openId, templateId);
        // 如果是access_token无效，就删了原来的access_token，再发一次模版消息
        if (result && JSON.parse(result).errcode === 40001) {
            fs.unlinkSync('access_token.json');
            return await this.sendWechatMsgMethod(url, data, openId, templateId);
        }
        return result;
    }

    /**
     * @desc 发送模版消息
     * @author zhu
     * @date 2018/5/4
     */
    public async sendWechatMsgMethod(url, data, openId, templateId) {
        return new Promise(async (resolve, reject) => {
            try {
                const postData: any = {};
                postData.touser = openId;
                postData.template_id = templateId;
                postData.data = data;
                if (url && url.length > 0) {
                    postData.url = url;
                }
                const jssdk = new Jsapi(this.app.config.weixin.appId, this.app.config.weixin.appSecret);
                const options = {
                    hostname: 'api.weixin.qq.com',
                    path: '/cgi-bin/message/template/send?access_token=' + await jssdk.getAccessToken(),
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/x-www-form-urlencoded',
                        'Content-Length': Buffer.byteLength(JSON.stringify(postData))
                    }
                };
                const req = https.request(options, (clientRes) => {
                    clientRes.setEncoding('utf8');
                    let reqData = "";
                    clientRes.on('data', (chunk) => {
                        reqData += chunk;
                    });
                    clientRes.on('end', () => {
                        this.ctx.logger.error("sendWechatMsg.openId=" + openId + ",result=" + reqData);
                        resolve(reqData);
                    });
                });
                req.on('error', (e) => {
                    this.ctx.logger.error(`problem with request: ${e}`);
                    reject(e);
                });
                req.write(JSON.stringify(postData));
                req.end();
            } catch (e) {
                this.ctx.logger.error("sendWechatMsg.error.open_id=" + openId, e);
                reject(e);
            }
        })
    }

    /**
     * 获取全部用户
     */
    public async getTokenList() {
        const queryStr = `
            SELECT
                u.user_openId 
            FROM
                t_user u
                INNER JOIN t_school s ON u.user_school_id = s.school_id 
                AND s.school_status = '1'
                INNER JOIN t_college c ON u.user_college_id = c.college_id 
                AND s.school_status = '1' 
            WHERE
                u.user_status <> '1'`;
        const result: any = await this.ctx.model.query(queryStr, {
            type: this.ctx.model.QueryTypes.SELECT,
        })
        if (result.length <= 0) {
            return '';
        } else {
            let open_id = '';
            const json: any = {};
            for (let i = 0; i < result.length; i++) {
                const user_openId = result[i].user_openId;
                if (user_openId && user_openId.length >= 0) {
                    let isRepeat = false;
                    for (let key in json) {
                        if (key == user_openId) {
                            isRepeat = true;
                            break;
                        }
                    }
                    if (isRepeat) {
                        continue;
                    } else {
                        json[user_openId] = 1;
                        open_id += user_openId + ',';
                    }
                }
            }
            if (open_id.length > 0) {
                open_id = open_id.substring(0, open_id.length - 1);
            }
            return open_id;
        }
    }

    /**
     * 发送通知
     * @param param 
     */
    public async sendNotifications(param: any) {
        const template_id = param.template_id;
        const user_list = param.open_id.split(',');
        const template_content = JSON.parse(param.template_content);
        let newData = {};
        for (const key in template_content) {
            newData[key] = { value: template_content[key] }
        }
        let success: number = 0;
        let fail: number = 0;
        const item: any = [];
        for (let i = 0; i < user_list.length; i++) {
            const url = 'https://www.baidu.com/';
            const result = await this.sendWechatMsg(url, newData, user_list[i], template_id);
            if (JSON.parse(result).errcode === 0) {
                success++;
                this.ctx.logger.info('发送成功');
            } else if (JSON.parse(result).errcode === 43004) {
                this.ctx.logger.error('客户已取消关注公众号！');
                fail++;
                const itemMsg: any = {};
                itemMsg.openId = user_list[i];
                itemMsg.msg = '客户已取消关注公众号！';
                item.push(itemMsg);
                continue;
                //throw new Error(JSON.stringify({ code: 2, msg: '客户已取消关注公众号！' }));
            } else {
                this.ctx.logger.error(result);
                fail++;
                const itemMsg: any = {};
                itemMsg.openId = user_list[i];
                itemMsg.msg = result;
                item.push(itemMsg);
                continue;
                //throw new Error(JSON.stringify({ code: 2, msg: result }));
            }
        }
        const result: any = { success, fail, failList: item };
        return result;
    }

    /**
     * 接收融云聊天消息
     */
    public async acceptCloundMessage(param: any) {
        const tran = await this.ctx.model.transaction();
        param.clound_message_id = param.msgUID;
        const createResult = await this.ctx.model.CloundMessage.create(param);
        if (!createResult) {
            throw new Error('创建失败');
        }
        try {
            const toUserId = param.toUserId;
            const fromUserId = param.fromUserId;
            await this.ctx.model.User.update({ is_online: '1', is_news: '2' }, { where: { user_id: fromUserId }, transaction: tran });
            const userResult: any = await this.ctx.model.User.findOne({ attributes: ['is_online', 'is_news'], where: { user_id: toUserId }, transaction: tran });
            if (!userResult) {
                throw new Error('找不到该用户');
            }
            const is_online = userResult.is_online;
            let updateResult: any = {};
            if (is_online == 1) {
                updateResult = await this.ctx.model.User.update({ is_news: '2' }, { where: { user_id: toUserId } });
            } else if (is_online == 2) {
                updateResult = await this.ctx.model.User.update({ is_news: '1' }, { where: { user_id: toUserId } });
            }
            if (updateResult[0] <= 0) {
                throw new Error('更新失败');
            }
            await tran.commit();
        } catch (e) {
            await tran.rollback();
            this.ctx.logger.error(e);
            throw new Error(JSON.stringify({ code: 2, msg: '接收成功' }));
        }
    }

}